#!/usr/bin/env python
""" AnyBackup is a windows specific backup program to keep multiple volumes in sync with multiple volumes
    Copyright (C) 2011  Andrew Hopkinson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    Exported Classes:
    
    ScrollingProgressDialog -- a dialog window with a progress bar which continually scrolls while
                               the dialog is displayed
    """

import wx
import os
import time
import datetime
from easyListCtrl import DictView


class FileProgressDialog(wx.Dialog):
    def __init__(self, parent, label, kill):
        wx.Dialog.__init__(self, parent, -1, label, wx.DefaultPosition, wx.Size(400, 350), wx.CAPTION | wx.SYSTEM_MENU)
        self.parent = parent
        self.kill = kill
        self.progressBar = wx.Gauge(self, -1, 100)
        self.totalProgressBar = wx.Gauge(self, -1, 100)
        self.count = 0
        self.toAdd = 1
        self.file = None
        self.drive = None
        self.lastDone = 0
        self.lastDoneTime = None
        self.start = time.time()
        if kill:
            self.cancel = wx.Button(self, 1, "Cancel")
        box = wx.BoxSizer(wx.VERTICAL)
        self.dataView = DictView(self, -1, size=wx.Size(390, 110))
        self.dataView.updateDict([
            ('Drive', ''),
            ('Drive Count', '? / ?'),
            ('File', ''),
            ('File Count', '? / ?'),
            ('Time Elapsed', '00:00:00'),
            ('Speed', '0kb/s')
        ])
        self.status = wx.StaticText(self, -1, 'Running Action...')
        box.Add(self.status, 0, wx.ALL | wx.EXPAND, 5)
        self.fileProgress = wx.StaticText(self, -1, 'Current File Progress')
        self.fileProgress.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))
        box.Add(self.fileProgress, 0, wx.ALL, 5)
        box.Add(self.progressBar, 0, wx.EXPAND | wx.ALL, 10)
        self.totalProgress = wx.StaticText(self, -1, 'Total Progress')
        self.totalProgress.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))
        box.Add(self.totalProgress, 0, wx.ALL, 5)
        box.Add(self.totalProgressBar, 0, wx.EXPAND | wx.ALL, 10)
        box.Add(self.dataView, 0, wx.EXPAND | wx.ALL, 5)
        if kill:
            box.Add(self.cancel, 0, wx.ALL | wx.ALIGN_RIGHT, 5)
        self.SetSizer(box)
        self.timer = wx.Timer(self, 0)
        self.checkThread = wx.Timer(self, 1)
        self.timer.Start(1000)
        self.checkThread.Start(2000)
        wx.EVT_TIMER(self, 0, self.updateGauge)
        wx.EVT_TIMER(self, 1, self.checkForThreadDeath)
        wx.EVT_BUTTON(self, 1, self.cancelAction)

    # noinspection PyMethodOverriding
    def Close(self, force=False):
        self.checkThread.Stop()
        self.timer.Stop()
        super(FileProgressDialog, self).Close(force=force)

    # noinspection PyUnusedLocal
    def checkForThreadDeath(self, event):
        if self.parent.thread.isAlive():
            return
        else:
            print 'dead'
            if not self.kill.is_set():
                wx.CallAfter(self.parent.threadError)
            self.Close(True)

    def cancelAction(self, event):
        bttn = event.GetEventObject()
        bttn.Disable()
        self.kill.set()
        self.status.SetLabel('Requesting Stop...')

    # noinspection PyUnusedLocal
    def updateGauge(self, event):
        fileName = self.parent.buManager.copyFrom
        drive = self.parent.buManager.currentDrive
        done = None
        self.dataView.updateDict([('Time Elapsed', datetime.timedelta(seconds=int(time.time()-self.start)))])
        if self.drive != drive:
            self.drive = drive
            self.dataView.updateDict([
                ('Drive', self.drive),
                ('Drive Count', '{0} / {1}'.format(
                    self.parent.buManager.driveFinished, self.parent.buManager.driveCount
                )),
            ])
        if self.file != fileName:
            self.file = fileName
            self.lastDone = 0
            self.total = 0
            self.progressBar.SetValue(0)
            if fileName:
                fileName = fileName.replace('\\\\?\\', '')
            short = fileName
            if fileName and len(fileName) > 60:
                short = '...'+fileName[-50:]
            self.dataView.updateDict([
                ('File', short),
                ('File Count', '{0} / {1}'.format(
                    self.parent.buManager.count, self.parent.buManager.total,
                ))
            ])
            if fileName:
                self.dataView.SetToolTip(wx.ToolTip(fileName))
            else:
                self.dataView.SetToolTip(wx.ToolTip('None'))
            self.fileProgress.SetLabel('Current File Progress')
            if self.parent.buManager.currentFile and self.parent.buManager.copyTo:
                self.startTime = time.time()
                self.total = os.path.getsize(self.file)/1024
                self.copyTo = os.path.join(self.parent.buManager.copyTo, self.parent.buManager.currentFile)
        if self.file:
            if os.path.exists(self.copyTo):
                done = os.path.getsize(self.copyTo)/1024
            else:
                done = 0
            if self.total:
                self.progressBar.SetValue(done*100/self.total)
            if self.startTime:
                delta = time.time() - self.startTime
                if delta:
                    speed = done/delta
                else:
                    speed = 0
                self.dataView.updateDict([('Speed', '{0:.0f}kb/s'.format(speed))])
                self.fileProgress.SetLabel('Current File Progress - ({0:.2f}mb / {1:.2f}mb)'.format(
                    done / 1024, self.total / 1024))
                self.totalProgress.SetLabel('Total Progress - ({0:.2f}mb / {1:.2f}mb)'.format(
                    self.parent.buManager.copyFinished / 1024, self.parent.buManager.copyTotal / 1024))
                self.lastDone = done
            else:
                self.lastDone = done
        if self.parent.buManager.copyTotal is not None and self.parent.buManager.copyTotal > 0:
            self.totalProgressBar.SetValue(self.parent.buManager.copyFinished*100 / self.parent.buManager.copyTotal)


class ScrollingProgressDialog(wx.Dialog):
    """ a dialog window with a progress bar which continually scrolls while the dialog is displayed """

    def __init__(self, parent, label, kill, fileDisp):
        wx.Dialog.__init__(self, parent, -1, label, wx.DefaultPosition, wx.Size(200, 175))
        self.parent = parent
        self.fileDisp = fileDisp
        self.kill = kill
        self.progressBar = wx.Gauge(self, -1, 80)
        self.count = 0
        self.toAdd = 10
        self.start = time.time()
        if self.kill:
            self.cancel = wx.Button(self, 1, "Cancel")
        box = wx.BoxSizer(wx.VERTICAL)
        self.status = wx.StaticText(self, -1, 'Running Action...')
        if fileDisp:
            self.fileLabel = wx.StaticText(self, -1, 'Found 0 file(s) so far...')
        self.timeLabel = wx.StaticText(self, -1, 'Time Elapsed: 00:00:00')
        box.Add(self.status, 0, wx.ALL | wx.EXPAND, 5)
        if fileDisp:
            box.Add(self.fileLabel, 0, wx.ALL | wx.EXPAND, 5)
        box.Add(self.progressBar, 0, wx.EXPAND | wx.ALL, 10)
        box.Add(self.timeLabel, 0, wx.ALL | wx.EXPAND, 5)
        if self.kill:
            box.Add(self.cancel, 0, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 5)
        self.SetSizer(box)
        self.timer = wx.Timer(self, 0)
        self.checkThread = wx.Timer(self, 1)
        self.timer.Start(2000)
        self.checkThread.Start(2000)
        wx.EVT_TIMER(self, 0, self.updateGauge)
        wx.EVT_TIMER(self, 1, self.checkForThreadDeath)
        wx.EVT_BUTTON(self, 1, self.cancelAction)

    # noinspection PyMethodOverriding
    def Close(self, force=False):
        self.checkThread.Stop()
        self.timer.Stop()
        super(ScrollingProgressDialog, self).Close(force=force)

    # noinspection PyUnusedLocal
    def checkForThreadDeath(self, event):
        if self.parent.thread.isAlive():
            return
        else:
            if not self.kill or (self.kill and not self.kill.is_set()):
                wx.CallAfter(self.parent.threadError)
            self.Close(True)

    def cancelAction(self, event):
        bttn = event.GetEventObject()
        bttn.Disable()
        self.kill.set()
        self.status.SetLabel('Requesting Stop...')

    # noinspection PyUnusedLocal
    def updateGauge(self, event):
        self.timeLabel.SetLabel('Time Elapsed: {0}'.format(datetime.timedelta(seconds=int(time.time()-self.start))))
        if self.fileDisp:
            self.fileLabel.SetLabel('Found {0} file(s) so far...'.format(self.parent.buManager.fileCount))
        self.count += self.toAdd
        if self.count > 100:
            self.count = 0
        self.progressBar.SetValue(self.count)


class ChkdskDialog(ScrollingProgressDialog):
    def __init__(self, parent, label, kill):
        wx.Dialog.__init__(self, parent, -1, label, wx.DefaultPosition, wx.Size(200, 175))
        self.parent = parent
        self.kill = kill
        self.count = 0
        self.toAdd = 10
        self.start = time.time()
        if self.kill:
            self.cancel = wx.Button(self, 1, "Cancel")
        box = wx.BoxSizer(wx.VERTICAL)
        self.status = wx.StaticText(self, -1, 'Running Action...')
        self.drive = wx.StaticText(self, -1, 'Drive: ?/?')
        self.timeLabel = wx.StaticText(self, -1, 'Time Elapsed: 00:00:00')
        box.Add(self.status, 0, wx.ALL | wx.EXPAND, 5)
        box.Add(self.drive, 0, wx.ALL, 5)
        box.Add(self.timeLabel, 0, wx.ALL | wx.EXPAND, 5)
        if self.kill:
            box.Add(self.cancel, 0, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 5)
        self.SetSizer(box)
        self.timer = wx.Timer(self, 0)
        self.checkThread = wx.Timer(self, 1)
        self.timer.Start(1000)
        self.checkThread.Start(2000)
        wx.EVT_TIMER(self, 0, self.updateGauge)
        wx.EVT_TIMER(self, 1, self.checkForThreadDeath)
        wx.EVT_BUTTON(self, 1, self.cancelAction)

    # noinspection PyUnusedLocal
    def updateGauge(self, event):
        self.timeLabel.SetLabel('Time Elapsed: {0}'.format(datetime.timedelta(seconds=int(time.time()-self.start))))
        self.drive.SetLabel('Drive: {0} / {1}'.format(self.parent.buManager.driveFinished,
                                                      self.parent.buManager.driveCount))

if __name__ == '__main__':
    import mock

    class someApp(wx.App):
        def OnInit(self):
            w = wx.Frame(None, -1, 'AnyBackup', wx.DefaultPosition, wx.Size(900, 700))
            w.thread = mock.MagicMock()
            w.thread.isAlive.return_value = True
            w.buManager = mock.MagicMock()
            w.buManager.copyFrom = 'Z:\\Cartoons\\Jumanji\\Season 1\\Jumanji - S01E01 - The Price.mp4'
            w.buManager.copyTo = 'C:\\some\\path'
            w.buManager.currentFile = 'Jumanji - S01E01 - The Price.mp4'
            w.buManager.currentDrive = 'drive1-123'
            w.buManager.driveFinished = 1
            w.buManager.driveCount = 2
            w.buManager.total = 20
            w.buManager.count = 3
            w.buManager.copyFinished = 238432
            w.buManager.copyTotal = 3843284
            # d = ScrollingProgressDialog(w, 'Test', None, False)
            d = FileProgressDialog(w, 'Test', True)
            d.Show()
            return True

    a = someApp(False)
    a.MainLoop()
